module Multi_ALU(
/* 8-bit ALU */
	iOP,		// ALUop [2:0]
	iA,		// input [7:0]
	iB,		// input [7:0]
	oResult,	// Arithmetic Result [7:0]
	oCarry,	// highest Carry
	oFlag		// [1]=zero, [0]=Overflow
	);
	
	input [2:0] iOP;
	input [7:0] iA, iB;

	output [7:0] oResult;
	output oCarry;
	output [1:0] oFlag;
	
	/*	iOP =	3'b000: and
				3'b001: or
				3'b010: add
				3'b110: subtract
				3'b111: set-on-less than: A>=B? ? 8'd0, A<B? ? 8'd1
												  A-B? MSB? ?? ????.
												  
				iOP[2] == 1??? ?? -> iB? ??? CLA? ????.
				??? iOP[2]? iB? ???? ??? ?? ????. */
	
	wire [7:0] wB = (iOP[2])? ~iB:iB;	// ??? ?? wire
	wire wCin_0 = (iOP[2])? 1'b1:1'b0;	// ??? ?? wire
	
	wire [7:0] wAND;
	wire [7:0] wOR_;
	wire [7:0] wSUM;
	wire [7:0] wSLT;
	wire wCout_8, wOverflow;
	
	assign wAND = iA & iB;
	assign wOR_ = iA | iB;
	assign wSLT = {7'd0, wSUM[7]|( (iA[7] == 0)&&(iA[7] == 1) )};
	
	assign oFlag[1] = (oResult == 8'd0)? 1'b1:1'b0;
	
	Adder_8_CLA adder(
	/* Carry Lookahead Adder */
		iA,			// input [7:0]
		wB,			// input [7:0]
		wCin_0,		// input Cin[0]
		wSUM,			// SUM [7:0]
		wCout_8,		// highest Carry
		wOverflow 	// overflow
		);
	
	/* ??? ????. */
	assign oResult = (iOP[1:0] == 2'b10)? wSUM : ( (iOP[2] == 1)? wSLT : ( (iOP[0] == 1)? wOR_:wAND ) ) ;
	assign oCarry = (iOP[1:0] == 2'b10)? wCout_8:1'b0;
	assign oFlag[0] = (iOP[1:0] == 2'b10)? wOverflow:1'b0;
	
endmodule

module Adder_8_CLA(
/* Carry Lookahead Adder */
	iA,			// input [7:0]
	iB,			// input [7:0]
	iCin_0,		// input Cin[0]
	oSUM,			// SUM [7:0]
	oCout_8,		// highest Carry
	oOverflow 	// overflow
	);

	input [7:0] iA, iB;
	input iCin_0;

	output [7:0] oSUM;
	output oCout_8;
	output oOverflow;
	
	wire [7:0] wCin;
	wire [7:0] wGen, wProp;	//Generate Carry, Propagate Carry
	
	assign wGen[7] = iA[7] & iB[7];
	assign wGen[6] = iA[6] & iB[6];
	assign wGen[5] = iA[5] & iB[5];
	assign wGen[4] = iA[4] & iB[4];
	assign wGen[3] = iA[3] & iB[3];
	assign wGen[2] = iA[2] & iB[2];
	assign wGen[1] = iA[1] & iB[1];
	assign wGen[0] = iA[0] & iB[0];
	
	assign wProp[7] = iA[7] ^ iB[7];
	assign wProp[6] = iA[6] ^ iB[6];
	assign wProp[5] = iA[5] ^ iB[5];
	assign wProp[4] = iA[4] ^ iB[4];
	assign wProp[3] = iA[3] ^ iB[3];
	assign wProp[2] = iA[2] ^ iB[2];
	assign wProp[1] = iA[1] ^ iB[1];
	assign wProp[0] = iA[0] ^ iB[0];
	
	assign oCout_8 = wGen[7] | (wProp[7] & wCin[7]);
	assign wCin[7] = wGen[6] | (wProp[6] & wCin[6]);
	assign wCin[6] = wGen[5] | (wProp[5] & wCin[5]);
	assign wCin[5] = wGen[4] | (wProp[4] & wCin[4]);
	assign wCin[4] = wGen[3] | (wProp[3] & wCin[3]);
	assign wCin[3] = wGen[2] | (wProp[2] & wCin[2]);
	assign wCin[2] = wGen[1] | (wProp[1] & wCin[1]);
	assign wCin[1] = wGen[0] | (wProp[0] & wCin[0]);
	assign wCin[0] = iCin_0;
	
	assign oOverflow = oCout_8 ^ wCin[7];
	
	assign oSUM[7] = wProp[7] ^ wCin[7];
	assign oSUM[6] = wProp[6] ^ wCin[6];
	assign oSUM[5] = wProp[5] ^ wCin[5];
	assign oSUM[4] = wProp[4] ^ wCin[4];
	assign oSUM[3] = wProp[3] ^ wCin[3];
	assign oSUM[2] = wProp[2] ^ wCin[2];
	assign oSUM[1] = wProp[1] ^ wCin[1];
	assign oSUM[0] = wProp[0] ^ wCin[0];

endmodule
